package com.yukefms.engine;

import com.yukefms.engine.interfaces.FMSEngine;
import com.yukefms.engine.interfaces.PointCloudReader;
import com.yukefms.engine.running.RunningContext;
import com.yukefms.engine.running.RunningEvent;
import com.yukefms.jointpoint.BodyPointCloud;
import com.yukefms.message.MessageContainer;
import com.yukefms.message.MessageProducer;
import com.yukefms.rule.interfaces.BARule;
import com.yukefms.rule.interfaces.BAStageRule;
import com.yukefms.rule.state.RuleStateFlyWeight;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Author Ping
 * @Date 2021/6/25 17:04
 **/
@Component("engine")
public class SimpleFMSEngine implements FMSEngine {
    public static Logger logger = LogManager.getLogger(SimpleFMSEngine.class);
    /**
     * the rule to be evaluated for bodyPoint stream
     */
    private BAStageRule rule ;
    /**
     * the context storing current bodyPoint, rule state, etc.
     */
    private RunningContext context ;
    /**
     * for input message
     */
    @Autowired
    private PointCloudReader reader ;
    /**
     * for output events
     */
//    @Autowired
//    private MessageContainer<RunningEvent> outContainer ;
    @Autowired
    MessageProducer producer ;
    /**
     * intializing all rule states before any actions.
     */
    static {
        RuleStateFlyWeight.doInit(null);
    }

    public SimpleFMSEngine() {

    }

    /**
     * for test add some consumer and producer.
     * @param rule
     */


    @Override
    public void setBARule(BAStageRule rule) {
        this.rule = rule ;
    }

    @Override
    public BAStageRule getBARule() {
        return this.rule ;
    }

    @Override
    public PointCloudReader getReader() {
        return this.reader ;
    }

    @Override
    public RunningContext currentContext() {
        return this.context;
    }

    @Override
    public void doInit() {

        this.context = new DefaultRunningContext(this.rule) ;

    }

    @Override
    public void doInit(MessageProducer producer) {
        this.context = new DefaultRunningContext(this.rule, producer) ;
    }

    @Override
    public void startup() {
        logger.error("FMSEngine started .") ;
        reader.start() ;
        logger.error("FMSEngine start to read pointCloud") ;
        while (true) {
            // read the head message
            BodyPointCloud pointCloud = this.reader.next() ;
//            System.out.println(pointCloud.toString());
            if (pointCloud == null) {
                //logger.error("Reading pointCloud failed.") ;
                //System.out.println("read  null");

            } else {
                // do the reaction

                rule.doReaction(pointCloud, context);
            }
            // update context
            // check if the result was gotten by query context
            if (context.ruleIsFinished() || this.reader.ended()) {
                shutdown() ;
                break ;
            }

        }
    }

    @Override
    public void shutdown() {
        logger.error("Now, the engine was stop.");
        this.reader.stop();
    }


    @Override
    public void setBARules(List<BAStageRule> ruleList) {

    }

    @Override
    public BAStageRule currentRule() {
        return this.rule;
    }

    @Override
    public boolean currentIsFinished() {
        return false;
    }

    @Override
    public boolean allFinished() {
        return false;
    }

    @Override
    public boolean hasNext() {
        return false;
    }

    @Override
    public void toNext() {

    }

    @Override
    public void resetContext(BAStageRule newRule) {

    }

    @Override
    public RunningContext getContextByRuleName(String ruleName) {
        return null;
    }

    @Override
    public Map<String, RunningContext> getRuleContextMap() {
        return null;
    }

    @Override
    public MessageProducer getProducer() {
        return this.producer;
    }
}
